#ifndef _BUOLA_CV_IO_CKINECTDEVICE_OPENNI_H_
#define _BUOLA_CV_IO_CKINECTDEVICE_OPENNI_H_

#include <buola/buola.h>
#include <buola/threads/thread.h>
#include <buola/threads/condition_variable.h>
#include <buola/utility/usignal.h>
#include <buola/image/point.h>

#include <atomic>
#include <XnCppWrapper.h>

namespace buola { namespace cvi {

class CKinectDevice
{
public:
    CKinectDevice(xn::Context &pXNContext,const xn::NodeInfo &pNodeInfo);
    ~CKinectDevice();
    
    void Start();
    void Stop();
    
    std::pair<img::CImage_rgb8,img::CImage_gray32f> GetOne();

    USignal<void(const img::CImage_rgb8&,const img::CImage_gray32f&)> sImages;
    
    const std::string &ConnectionString()   {   return mConnectionString;   }

private:
    bool HasDepthStream();
    bool HasImageStream();
    bool HasIRStream();
    
    uint64_t GetIntProperty(const std::string &pName);
    double GetDoubleProperty(const std::string &pName);
    
    void SetIntProperty(const std::string &pName,uint64_t pValue);
    void SetDoubleProperty(const std::string &pName,double pValue);
    
    void Initialize();

    void OnThread();
    
    void DoStart();
    void DoStop();
    void DoIteration(int pCount);
    
private:
    xn::Context &mXNContext;
    xn::Device mXNDevice;
    xn::NodeInfo mDeviceInfo;
    std::string mConnectionString;
    
    std::atomic<bool> mInitialized;

    std::vector<XnMapOutputMode> mAvailableImageModes;
    std::vector<XnMapOutputMode> mAvailableDepthModes;

    xn::DepthGenerator mDepthGenerator;
    xn::ImageGenerator mImageGenerator;
    xn::IRGenerator mIRGenerator;

    ///focal length for IR camera producing depth information in native SXGA mode
    float mDepthFocalLengthSXGA;
    ///distance between the projector and the IR camera
    float mBaseline;
    ///focal length for regular camera producing color images in native SXGA mode
    float mRGBFocalLengthSXGA;

    /** the value for shadow (occluded pixels) */
    XnUInt64 mShadowValue;
    /** the value for pixels without a valid disparity measurement */
    XnUInt64 mNoSampleValue;

    thread mThread;
    mutex mMutex;
    condition_variable mCondVar;

    int mSyncIndex;
    mutex mSyncMutex;
    condition_variable mSyncCondVar;
    img::CImage_rgb8 mSyncImageRGB;
    img::CImage_gray32f mSyncImageDepth;
    
    std::atomic<int> mStartCount;    
    
    bool mStarted;
};

/*namespace cvi*/ } /*namespace buola*/ }

#endif
